<!DOCTYPE html>
<html lang="en">
<head>
  <title>Configuration - Born to build better enterprise frameworks and apps</title>
  <meta charset="utf-8">
  <meta name="description" content="index.description">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <link rel="icon" href="/images/favicon.png" type="image/x-icon">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css" />
<link rel="stylesheet" href="/css/index.css">

    <script>
    !function(t,e,a,r,c){t.TracertCmdCache=t.TracertCmdCache||[],t[c]=window[c]||
      {_isInit:!0,call:function(){t.TracertCmdCache.push(arguments)},
      start:function(t){this.call('start',t)}},t[c].l=new Date;
      var n=e.createElement(a),s=e.getElementsByTagName(a)[0];
      n.async=!0,n.src=r,s.parentNode.insertBefore(n,s)}
    (window,document,'script','https://tracert.alipay.com/tracert.js','Tracert');
      Tracert.start({
        plugins: [ 'BucName' ],
        spmAPos: 'a454',
        spmBPos: 'b4893',
      });
    </script>
  
</head>
<body>
  <div class="nav" >
  <header>
    <a href="/en/" class="nav-logo leftpadding" alt="egg"><img src="https://zos.alipayobjects.com/rmsportal/VTcUYAaoKqXyHJbLAPyF.svg"></a>
    <ul class="nav-item">
      <li>
        <form id="search-form">
          <input type="text" id="search-query" class="search-query st-default-search-input">
        </form>
      </li>
      <li><a href="/en/intro/" alt="Guide">Guide</a></li><li><a href="/api/" alt="API">API</a></li><li><a href="/en/tutorials/index.html" alt="Tutorials">Tutorials</a></li><li><a href="https://github.com/search?q=topic%3Aegg-plugin&type=Repositories" alt="Plugins">Plugins</a></li><li><a href="https://github.com/eggjs/egg/releases" alt="Release">Release</a></li>
      
      
        <li class="translations">
          <a class="nav-link">中文文档</a>
          <span class="arrow"></span><ul id="dropdownContent" class="dropdown-content"><li><a id="en" href="/en/basics/config.html" style="color: #22ab28">English</a></li><li><a id="zh-cn" href="/zh-cn/basics/config.html" >中文</a></li></ul>
        </li>
      
      <li><iframe src="https://ghbtns.com/github-btn.html?user=eggjs&repo=egg&type=star&count=true" frameborder="0" scrolling="0" width="150px" height="20px"></iframe></li>
    </ul>
    <a id="mobileTrigger" href="#" class="mobile-trigger">
      <ul>
        <li></li>
        <li></li>
        <li></li>
      </ul>
    </a>
  </header>
</div>
  <div id="container" class="container">
    <div class="page-main">
  <article class="markdown-body">
    <h1>Configuration</h1>
    <p>This framework provides powerful and extensible configuration function, including automatically merging applications, plugins, and framework's configuration. In addition, it allows users to overwrite configuration in sequence and maintain different configs depending on different environments. The result (i.e. merged config) can be accessed from <code>app.config</code>.</p>
<p>Here are some common control tactics:</p>
<ol>
<li>Using platform to manage configurations: while building a new application, you can put the current environment configuration into package and trigger the configuration as long as you run this application. But this certain application won't be able to build several deployments at once, and you will get into trouble whenever you want to use the configuration in localhost.</li>
<li>Using platform to manage configurations: you can pass the current environment configuration via environment variables while starting. This is a relatively elegant approach with higher requirement on operation and support from configuration platform. Moreover, The configuration environment has same flaws as first method.</li>
<li>Using code to manage configurations: you can add some environment configurations in codes and pass them  to current environment arguments while starting. However, it doesn't allow you to configure globally and you need to alter your code whenever you want to change the configuration.</li>
</ol>
<p>we choose the last strategy, namely <strong>configure with code</strong>, The change of configuration should be also released after reviewing. The application package itself is capable to be deployed in several environments, only need to specify the running environment.</p>
<h3 id="multiple-environment-configuration"><a class="markdown-anchor" href="#multiple-environment-configuration">#</a> Multiple environment configuration</h3>
<p>This framework supports loading configuration according to the environment and defining configuration files of multiple environments. For more details, please check <a href="../basics/env.html">env</a>.</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">config</span><br><span class="line">|- config.default.js</span><br><span class="line">|- config.test.js</span><br><span class="line">|- config.prod.js</span><br><span class="line">|- config.unittest.js</span><br><span class="line">|- config.local.js</span><br></pre></td></tr></table></figure>
<p><code>config.default.js</code> is the default file for configuration, and all environments will load this file. Besides, this is usually used as default configuration file for development environment.</p>
<p>The corresponding configuration file will be loaded simultaneously when you set up env and the default configuration with the same name will be overwritten. For example, <code>prod</code> environment will load <code>config.prod.js</code> and <code>config.default.js</code>. As a result, <code>config.prod.js</code> will overwrite the configuration with identical name in <code>config.default.js</code>.</p>
<h3 id="how-to-write-configuration"><a class="markdown-anchor" href="#how-to-write-configuration">#</a> How to write configuration</h3>
<p>The configuration file returns an object which could overwrite some configurations in the framework. Application can put its own business configuration into it for convenient management.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// configure the catalog of logger，the default configuration of logger is provided by framework</span></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  logger: &#123;</span><br><span class="line">    dir: <span class="string">'/home/admin/logs/demoapp'</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>The configuration file can simplify to <code>exports.key = value</code> format</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">exports.keys = <span class="string">'my-cookie-secret-key'</span>;</span><br><span class="line">exports.logger = &#123;</span><br><span class="line">  level: <span class="string">'DEBUG'</span>,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>The configuration file can also return a function which could receive a parameter called <code>appInfo</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// put the catalog of logger to the catalog of codes</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="params">appInfo</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    logger: &#123;</span><br><span class="line">      dir: path.join(appInfo.baseDir, <span class="string">'logs'</span>),</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>The build-in appInfo contains:</p>
<table>
<thead>
<tr>
<th>appInfo</th>
<th>elaboration</th>
</tr>
</thead>
<tbody>
<tr>
<td>pkg</td>
<td>package.json</td>
</tr>
<tr>
<td>name</td>
<td>Application name, same as pkg.name</td>
</tr>
<tr>
<td>baseDir</td>
<td>The directory of codes</td>
</tr>
<tr>
<td>HOME</td>
<td>User directory, e.g, the account of admin is /home/admin</td>
</tr>
<tr>
<td>root</td>
<td>The application root directory, if the environment is local or unittest, it is baseDir. Otherwise, it is HOME</td>
</tr>
</tbody>
</table>
<p><code>appInfo.root</code> is an elegant adaption. for example, we tend to use <code>/home/admin/logs</code> as the catalog of log in the server environment, while we don't want to pollute the user catalog in local development. This adaptation is very good at solving this problem.</p>
<p>Choose the appropriate style according to the specific situation, but please make sure you don't make mistake like the code below:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// config/config.default.js</span></span><br><span class="line">exports.someKeys = <span class="string">'abc'</span>;</span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="params">appInfo</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> config = &#123;&#125;;</span><br><span class="line">  config.keys = <span class="string">'123456'</span>;</span><br><span class="line">  <span class="keyword">return</span> config;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="sequence-of-loading-configurations"><a class="markdown-anchor" href="#sequence-of-loading-configurations">#</a> Sequence of loading configurations</h3>
<p>Applications, plugin components and framework are able to define those configs. Even though the structure of catalog is identical but there is priority (application &gt; framework &gt; plugin). Besides, the running environment has the higher priority.</p>
<p>Here is one sequence of loading configurations under &quot;prod&quot; environment, in which the following configuration will overwrite the previous configuration with the same name.</p>
<pre><code>-&gt; plugin config.default.js
-&gt; framework config.default.js
-&gt; application config.default.js
-&gt; plugin config.prod.js
-&gt; framework config.prod.js
-&gt; application config.prod.js
</code></pre>
<p><strong>Note: there will be plugin loading sequence, but the approximate order is similar. For specific logic, please check the <a href="../advanced/loader.html">loader</a> .</strong></p>
<h3 id="merging-rule"><a class="markdown-anchor" href="#merging-rule">#</a> Merging rule</h3>
<p>Configs are merged using deep copy from [extend2] module, which is forked from [extend] and process array in a different way.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> a = &#123;</span><br><span class="line">  arr: [ <span class="number">1</span>, <span class="number">2</span> ],</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">const</span> b = &#123;</span><br><span class="line">  arr: [ <span class="number">3</span> ],</span><br><span class="line">&#125;;</span><br><span class="line">extend(<span class="literal">true</span>, a, b);</span><br><span class="line"><span class="comment">// =&gt; &#123; arr: [ 3 ] &#125;</span></span><br></pre></td></tr></table></figure>
<p>As demonstrated above, the framework will overwrite arrays instead of merging them.</p>
<h2 id="configuration-result"><a class="markdown-anchor" href="#configuration-result">#</a> Configuration result</h2>
<p>The final merged config will be dumped to <code>run/application_config.json</code>(for worker process) and <code>run/agent_config.json</code>(for agent process) when the framework started, which can help analyzing problems.</p>
<p>Some fields are hidden in the config file, mainly including 2 types:</p>
<ul>
<li>like passwords, secret keys and other security related fields which can be configured in <code>config.dump.ignore</code> and only <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set" target="_blank" rel="noopener">Set</a> type is accepted. See <a href="https://github.com/eggjs/egg/blob/master/config/config.default.js" target="_blank" rel="noopener">Default Configs</a></li>
<li>like Function, Buffer, etc. whose content converted by <code>JSON.stringify</code> will be specially large.</li>
</ul>
<p><code>run/application_config_meta.json</code> (for worker process）and <code>run/agent_config_meta.json</code> (for agent process) will also be dumped in order to check which file defines the property, see below</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"logger"</span>: &#123;</span><br><span class="line">    <span class="attr">"dir"</span>: <span class="string">"/path/to/config/config.default.js"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

  </article>
  <aside id="mobileAside" class="toc">
  <div class="mobile-menu">
    <ul>
      <li><a href="/en/intro/" alt="Guide">Guide</a></li><li><a href="/api/" alt="API">API</a></li><li><a href="/en/tutorials/index.html" alt="Tutorials">Tutorials</a></li><li><a href="https://github.com/search?q=topic%3Aegg-plugin&type=Repositories" alt="Plugins">Plugins</a></li><li><a href="https://github.com/eggjs/egg/releases" alt="Release">Release</a></li>
      
      
        <li class="translations">
          <a class="nav-link">中文文档</a>
          <span class="arrow"></span><ul id="dropdownContent" class="dropdown-content"><li><a id="en" href="/en/basics/config.html" style="color: #22ab28">English</a></li><li><a id="zh-cn" href="/zh-cn/basics/config.html" >中文</a></li></ul>
        </li>
      
    </ul>
  </div>
  <dl><dt id="title-Intro" style="cursor: pointer;" class="aside-title">Guide<a id="collapse-icon-Intro" class="icon opend"></a></dt><dd id=panel-Intro><ul><li><a href="/en/intro/index.html" class="menu-link">What is Egg?</a></li><li><a href="/en/intro/egg-and-koa.html" class="menu-link">Egg and Koa</a></li><li><a href="/en/intro/quickstart.html" class="menu-link">Quick Start</a></li><li><a href="/en/tutorials/progressive.html" class="menu-link">Progressive</a></li><li><a href="/en/migration.html" class="menu-link">Migration to 2.x</a></li></ul></dd><dt id="title-Basics" style="cursor: pointer;" class="aside-title">Basis Function<a id="collapse-icon-Basics" class="icon opend"></a></dt><dd id=panel-Basics><ul><li><a href="/en/basics/structure.html" class="menu-link">Directory Structure</a></li><li><a href="/en/basics/objects.html" class="menu-link">Built-in Objects</a></li><li><a href="/en/basics/env.html" class="menu-link">Environment</a></li><li><a href="/en/basics/config.html" class="menu-link">Configuration</a></li><li><a href="/en/basics/middleware.html" class="menu-link">Middleware</a></li><li><a href="/en/basics/router.html" class="menu-link">Router</a></li><li><a href="/en/basics/controller.html" class="menu-link">Controller</a></li><li><a href="/en/basics/service.html" class="menu-link">Service</a></li><li><a href="/en/basics/plugin.html" class="menu-link">Plugin</a></li><li><a href="/en/basics/schedule.html" class="menu-link">Schedule</a></li><li><a href="/en/basics/extend.html" class="menu-link">Extend</a></li><li><a href="/en/basics/app-start.html" class="menu-link">Custom Init</a></li></ul></dd><dt id="title-Core" style="cursor: pointer;" class="aside-title">Core<a id="collapse-icon-Core" class="icon opend"></a></dt><dd id=panel-Core><ul><li><a href="/en/core/development.html" class="menu-link">Development</a></li><li><a href="/en/core/unittest.html" class="menu-link">Unit Testing</a></li><li><a href="/en/core/deployment.html" class="menu-link">Deployment</a></li><li><a href="/en/core/logger.html" class="menu-link">Logger</a></li><li><a href="/en/core/httpclient.html" class="menu-link">HttpClient</a></li><li><a href="/en/core/cookie-and-session.html" class="menu-link">Cookie and Session</a></li><li><a href="/en/core/cluster-and-ipc.html" class="menu-link">Cluster and IPC</a></li><li><a href="/en/core/view.html" class="menu-link">View</a></li><li><a href="/en/core/error-handling.html" class="menu-link">Error Handling</a></li><li><a href="/en/core/security.html" class="menu-link">Security</a></li><li><a href="/en/core/i18n.html" class="menu-link">i18n</a></li></ul></dd><dt id="title-Tutorials" style="cursor: pointer;" class="aside-title">Tutorials<a id="collapse-icon-Tutorials" class="icon opend"></a></dt><dd id=panel-Tutorials><ul><li><a href="/en/tutorials/mysql.html" class="menu-link">MySQL</a></li><li><a href="/en/tutorials/restful.html" class="menu-link">RESTful API</a></li><li><a href="/en/tutorials/passport.html" class="menu-link">Passport</a></li><li><a href="/en/tutorials/socketio.html" class="menu-link">Socket.IO</a></li><li><a href="/en/tutorials/assets.html" class="menu-link">Assets</a></li><li><a href="/en/tutorials/typescript.html" class="menu-link">TypeScript</a></li></ul></dd><dt id="title-Advanced" style="cursor: pointer;" class="aside-title">Advanced<a id="collapse-icon-Advanced" class="icon opend"></a></dt><dd id=panel-Advanced><ul><li><a href="/en/advanced/loader.html" class="menu-link">Loader</a></li><li><a href="/en/advanced/plugin.html" class="menu-link">Plugin Development</a></li><li><a href="/en/advanced/framework.html" class="menu-link">Framework</a></li><li><a href="/en/advanced/cluster-client.html" class="menu-link">Cluster Enhancement</a></li><li><a href="/en/advanced/view-plugin.html" class="menu-link">View Plugin</a></li><li><a href="/en/style-guide.html" class="menu-link">Style Guide</a></li></ul></dd><dt id="title-Community" style="cursor: pointer;" class="aside-title">Community<a id="collapse-icon-Community" class="icon opend"></a></dt><dd id=panel-Community><ul><li><a href="/en/plugins/" class="menu-link">Plugin List</a></li><li><a href="/en/contributing.html" class="menu-link">Contributing</a></li><li><a href="/en/resource.html" class="menu-link">Resource</a></li><li><a href="/en/faq.html" class="menu-link">FAQ</a></li></ul></dd></dl>
</aside>
<script>
var mobileTrigger = document.getElementById('mobileTrigger');
var mobileAside = document.getElementById('mobileAside');

var expandMenu = function(title) {
  // handle icon
  const collapseIcon = document.getElementById('collapse-icon-' + title);
  if (collapseIcon) {
    collapseIcon.className = 'icon opend';
  }
  // handle panelEle
  const panelEle = document.getElementById('panel-' + title);
  if (panelEle) {
    panelEle.className = '';
  }
}

var collapseMenu = function(title) {
  // handle icon
  const collapseIcon = document.getElementById('collapse-icon-' + title);
  if (collapseIcon) {
    collapseIcon.className = 'icon closed';
  }
  // handle panelEle
  const panelEle = document.getElementById('panel-' + title);
  if (panelEle) {
    panelEle.className = 'aside-panel-hidden';
  }
}

mobileAside.onclick = function(e) {
  const targetId = e.target.id;
  if (targetId && (targetId.indexOf('title-') > -1 || targetId.indexOf('collapse-icon-') > -1)) {
    const title = targetId.replace('title-', '').replace('collapse-icon-', '');
    try { 
      // the the browser may have no localStroage or JSON.parse may throw exception.
      const menuInfo = JSON.parse(window.localStorage.getItem('menuInfo'));
        
      // current menu status
      const curClosed = menuInfo[title] ? menuInfo[title].closed : false; // default false

      // change UI
      curClosed ? expandMenu(title) : collapseMenu(title);

      // save menuInfo to localStorage
      menuInfo[title] = { closed: !curClosed } // opposite
      window.localStorage.setItem('menuInfo', JSON.stringify(menuInfo));
    } catch (e) {}
  }
};

mobileTrigger.onclick = function(e) {
  e.preventDefault();
  if (mobileAside.className.indexOf('mobile-show') === -1) {
    mobileAside.className += ' mobile-show';
  } else {
    mobileAside.className = 'toc';
  }
};

(function() {
  // save data to localStorage because the page will refresh when user change the url.
  let menuInfo;
  try { 
    // the the browser may have no localStroage or JSON.parse may throw exception.
    menuInfo = JSON.parse(window.localStorage.getItem('menuInfo'));
    if (!menuInfo) {
      menuInfo = {};
      window.localStorage.setItem('menuInfo', JSON.stringify(menuInfo));
    }
  } catch (e) {
    menuInfo = {}; // default {}
  }

  for (const title in menuInfo) {
    if (menuInfo[title] && menuInfo[title].closed) { // menu in closed status.
      collapseMenu(title);
    } else {
      expandMenu(title);
    }
  }

  // highlight menu
  const pathname = window.location.pathname;
  const selector = `a[href="${pathname}"].menu-link,a[href="${pathname}index.html"].menu-link`;
  const menuItem = mobileAside.querySelector(selector);
  if (menuItem) { menuItem.className += ' highlight'; }
})();
</script>

</div>

  </div>
</body>
<script src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script>
<script>
docsearch({
  apiKey: '1561de31a86f79507ea00cdb54ce647c',
  indexName: 'eggjs',
  inputSelector: '#search-query',
});
</script>
<div class="cnzz">
<script src="https://s11.cnzz.com/z_stat.php?id=1261142226&web_id=1261142226" language="JavaScript"></script>
</div>

</html>
